﻿using System;
using System.ComponentModel;
using DBServer.Selenium.Extenium.Exception;
using DBServer.Selenium.Extenium.Path;
using Selenium;
using System.Linq;

namespace DBServer.Selenium.Extenium.Fixtures
{
    public class GridFixture : ExtComponentFixture
    {
        protected readonly ISelenium _driver;
        protected readonly string _name;

        public GridFixture(ISelenium driver, string name) : base(driver, new ExtComponentPath(name))
        {
            _driver = driver;
            _name = name;
        }

        protected void RequireStoreIsLoaded()
        {
            Wait(() => (int.Parse(SafeExec(Path.Eval() + ".store.data.length"))) != 0);
        }


        protected void RequireGridNotLoading()
        {
            Wait(() => SafeExec(Path.Eval() + "loadMask.el.dom.childNodes["+ Path.Eval()+ ".loadMask.el.dom.childNodes.length-1].attributes.item('class')") != "class=\"ext-el-mask-msg x-mask-loading\"");
        }

        public GridFixture GoToPageContaining(string value)
        {
            if (IsCellContainingValuePresent(value))
            {
                return this;
            }

            FirstPage();
            var pageCount = PageCount();
            for (var page = 1; page <= pageCount; page++)
            {
                if (IsCellContainingValuePresent(value))
                {
                    return this;
                }
                if (page < pageCount)
                {
                    NextPage();
                }
            }

            throw new ExteniumException("Cell not found: " + value);
        }

        private bool IsCellContainingValuePresent(string value)
        {
            var command =
                " var value = '" + value + "';                                                                                              " +
                " var grid = " + Path.Eval() + ";                                                                                           " +                
                " var toolbar = grid.getBottomToolbar();                                                                                    " +
                " var totalPages = toolbar.getPageData().pages;                                                                             " +
                " var isValuePresent = function(grid, value) {                                                                              " +
                "    var rows = grid.getView().getRows().length;                                                                            " +
                "    var columns = grid.colModel.columns.length;                                                                            " +
                "    for (var row = 0; row < rows; row++) {                                                                                 " +
                "       for (var column = 0; column < columns; column++) {                                                                  " +
                "          var content = window.Ext.fly(grid.getView().getCell(row, column)).child('div.x-grid3-cell-inner').dom.innerHTML; " +
                "          if (content.indexOf(value) >= 0) {                                                                               " +
                "             return true;                                                                                                  " +
                "          }                                                                                                                " +
                "       }                                                                                                                   " +
                "    }                                                                                                                      " +
                "    return false;                                                                                                          " +
                " };                                                                                                                        " +
                " isValuePresent(grid, value);                                                                                              ";

            RequireStoreIsLoaded();
            return bool.Parse(SafeExec(command));
        }

        //public RowFixture RowContaining(string value)
        //{

        //    var command =
        //        " var value = '" + value + "'; " +
        //        " var grid = " + Path.Eval() + "; " +                
        //        " var RowContainingIgnoreCase = function(grid, value) { " +
        //        "     var rows = grid.getView().getRows().length; " +
        //        "     var columns = grid.colModel.columns.length; " +
        //        "     value = value.toUpperCase(); " +
        //        "     for (var row = 0; row < rows; row++) { " +
        //        "         for (var column = 0; column < columns; column++) { " +
        //        "             var content = window.Ext.fly(grid.getView().getCell(row, column)).child('div.x-grid3-cell-inner').dom.innerHTML; " +
        //        "             content = content.toUpperCase(); " +
        //        "             if (content.indexOf(value) >= 0) { " +
        //        "                 return row; " +
        //        "             } " +
        //        "         } " +
        //        "     } " +
        //        "     return -1; " +
        //        " }; " +
        //        " RowContainingIgnoreCase(grid, value); ";

        //    RequireStoreIsLoaded();
        //    var row = int.Parse(SafeExec(command));

        //    if ( row >= 0 )
        //    {
        //        return new RowFixture(_driver, _name, row);
        //    }
        //    throw new ExteniumException("Could not find row containing value: " + value);
        //}






        public GridFixture GridNotContaining(string value)
        {

            var command =
                " var value = '" + value + "'; " +
                " var grid = " + Path.Eval() + "; " +
                " var RowContainingIgnoreCase = function(grid, value) { " +
                "     var rows = grid.getView().getRows().length; " +
                "     var columns = grid.colModel.columns.length; " +
                "     value = value.toUpperCase(); " +
                "     for (var row = 0; row < rows; row++) { " +
                "         for (var column = 0; column < columns; column++) { " +
                "             var content = window.Ext.fly(grid.getView().getCell(row, column)).child('div.x-grid3-cell-inner').dom.innerHTML; " +
                "             content = content.toUpperCase(); " +
                "             if (content.indexOf(value) >= 0) { " +
                "                 return row; " +
                "             } " +
                "         } " +
                "     } " +
                "     return -1; " +
                " }; " +
                " RowContainingIgnoreCase(grid, value); ";

            RequireGridNotLoading();
            var row = int.Parse(SafeExec(command));

            if (row < 0)
            {
                return this;
            }
            throw new ExteniumException("Founded row(s) containing value: " + value);
        }



        protected int RowsInGrid()
        {
            var eval = SafeExec(Path + ".getBottomToolbar().store.totalLength;");
            return int.Parse(eval);
        }

        protected int RowsInCurrentPage()
        {
            var eval = SafeExec(Path + ".getView().getRows().length;");
            return int.Parse(eval);
        }

        protected int ColumnCount()
        {
            var eval = SafeExec(Path + ".colModel.columns.length;");
            return int.Parse(eval);
        }

        public GridFixture NextPage()
        {
            var nextPage = ActivePage() + 1;
            ValidatePage(nextPage);
            SafeExec(Path + ".getBottomToolbar().moveNext();");
            Wait(ActivePagePageIs(nextPage));
            return this;
        }

        public GridFixture PreviousPage()
        {
            var previousPage = ActivePage() - 1;
            ValidatePage(previousPage);
            SafeExec(Path + ".getBottomToolbar().movePrevious();");
            Wait(ActivePagePageIs(previousPage));
            return this;
        }


        public GridFixture LastPage()
        {
            var pageCount = PageCount();
            ValidatePage(pageCount);
            SafeExec(Path + ".getBottomToolbar().moveLast();");
            Wait(ActivePagePageIs(pageCount));
            return this;
        }

        public GridFixture FirstPage()
        {
            SafeExec(Path + ".getBottomToolbar().moveFirst();");
            Wait(ActivePagePageIs(1));
            return this;
        }

        public int RowsPerPage()
        {
            var eval = SafeExec(Path + ".getBottomToolbar().pageSize;");
            return int.Parse(eval);
        }

        private void ValidatePage(int pageIndex)
        {
            if (pageIndex <= 0 || pageIndex > PageCount())
            {
                throw new ExteniumException("Page out of range: " + pageIndex);
            }
        }

        public RowFixture RowContaining(params string[] value)
        {
            //Cria um array na forma "[ 'value[0]', 'value[1]', 'value[2]' ]"
            var array = "[" + String.Join(",", value.Select(e => "'" + e + "'").ToArray()) + "]";

            var command =
                "var criterias = " + array + ";" +
                "var grid =   " + Path.Eval() + "; " +

                "var RowContainingIgnoreCase = function(grid, criterias) {  " +
                "   var rows = grid.getView().getRows().length;  " +
                "   var columns = grid.colModel.columns.length;  " +
                "   var indexof;" +
                "   var criteria;" +

                "   for (var row = 0; row < rows; row++)  " +
                "   {" +
                "       var contains = 0;" +

                "       for(var i =0; i < criterias.length; i++)" +
                "       {" +
                "           criteria = criterias[i].toUpperCase();  " +
                "           indexof = grid.getView().getRow(row).innerHTML.toUpperCase().indexOf(criteria);" +

                "           if(indexof > 0)" +
                "               contains++;" +
                "           else " +
                "               break;" +
                "       }" +

                "       if(contains == criterias.length) " +
                "           return row;" +

                "   }" +
                "   return -1;" +
                "}; " +
                "RowContainingIgnoreCase(grid, criterias);";

            RequireStoreIsLoaded();
            var row = int.Parse(SafeExec(command));

            if (row >= 0)
            {
                return new RowFixture(_driver, _name, row);
            }
            throw new ExteniumException("Could not find row containing value: " + value);
        }

        protected int PageCount()
        {
            return int.Parse(SafeExec(Path + ".getBottomToolbar().getPageData().pages;"));
        }

        private int ActivePage()
        {
            return int.Parse(SafeExec(Path + ".getBottomToolbar().getPageData().activePage;"));
        }

        private Condition ActivePagePageIs(int pageIndex)
        {
            return () => ActivePage() == pageIndex;
        }

        public GridFixture RequireRowCount(int numberOfRows)
        {
            RequireGridNotLoading();
            if (numberOfRows == RowsInGrid())
            {
                return this;
            }
            throw new ExteniumException("Number of rows not equal " + numberOfRows);
        }

        public GridFixture RequireColumnFormat(string columnName, string format)
        {
            RequireStoreIsLoaded();
            var indexOfColumn = getColumnByName(columnName);
            var actualPage = this.ActivePage();
            this.FirstPage();
            for (int i = 0; i < RowsInGrid(); i++)
            {
                var stringFromGrid = getRowByIndex(i).CellAtColumn(indexOfColumn).GetValue();
                var stringWithoutFormat = RemoveSpecialChar(stringFromGrid);

                MaskedTextProvider mascara = new MaskedTextProvider(format);
                mascara.Set(stringWithoutFormat);
                if( mascara.ToDisplayString() != stringFromGrid)
                {
                    throw new ExteniumException("Text of " + columnName + " in row: " + i + " was not in the correct format.");     
                }
            }
            return this;
        }

        private static string RemoveSpecialChar(string stringWithSpecialChars)
        {
            string stringWithoutSpecialChars = stringWithSpecialChars;
            stringWithoutSpecialChars = stringWithoutSpecialChars.Replace(".", "");
            stringWithoutSpecialChars = stringWithoutSpecialChars.Replace("-", "");
            stringWithoutSpecialChars = stringWithoutSpecialChars.Replace("/", "");
            stringWithoutSpecialChars = stringWithoutSpecialChars.Replace("\\", "");
            stringWithoutSpecialChars = stringWithoutSpecialChars.Replace("(", "");
            stringWithoutSpecialChars = stringWithoutSpecialChars.Replace(")", "");
            return stringWithoutSpecialChars;
        }

        private int getColumnByName(string columnName)
        {

            var command =
                " function getColumnByName() { " +
                " var columnName = '" + columnName + "'; " +
                " var grid = " + Path.Eval() + "; " +
                " for(var i=0; i < grid.colModel.columns.length; i++) " +
                " { " +
                "       if(grid.colModel.columns[i].header == columnName)" +
                "       { " +
                "           return i;" +
                "       }" +
                " } " +
                " return -1;" + 
                " } " +
                "getColumnByName();";

             RequireStoreIsLoaded();
             var indexOfColumn = int.Parse(SafeExec(command));
             if (indexOfColumn < 0)
             {
                throw new ExteniumException("Column not founded with name: " + columnName);
             }
             return indexOfColumn;
        }


        private RowFixture getRowByIndex(int rowIndex)
        {
            var command =
                " function movePageToIndex() { " +
                "   var index = " + rowIndex.ToString() + ";" +
                "   var grid = " + Path.Eval() + ";" +
                "   while(index > grid.getBottomToolbar().pageSize) " +
                "   { " +
                "       grid.getBottomToolbar().moveNext();" +
                "       index = index - grid.getBottomToolbar().pageSize; " +
                "   } " +
                " return index; " +
                " } " +
                " movePageToIndex();";

            RequireStoreIsLoaded();
            var row = int.Parse(SafeExec(command));

            if (row >= 0)
            {
                return new RowFixture(_driver, _name, row);
            }
            throw new ExteniumException("Could not find row containing value: " + rowIndex);
        }
    }

}
